package com.example.controlleradvice.global;

import com.example.controlleradvice.system.SystemErrorControllerAdvice;
import com.example.exception.*;
import com.example.exception.db.UpdateTableRecordException;
import com.example.response.ErrorStatus;
import com.example.response.ApiResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.BindException;
import org.springframework.web.bind.MissingRequestHeaderException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.Set;

/**
 * 用于捕获所有控制器可能出现的各种异常, 此控制器捕获的异常类型之间不能含有继承关系
 * 如{@code @ExceptionHandler} 注解的 value 不能是 Exception.class, 防止异常处理器无法被正确调用
 * 未被此选择器捕获的异常, 都将在 {@link SystemErrorControllerAdvice} 中捕获
 * @author LeXin Huang
 * @date 2021年04月05日 13:20
 */
@Slf4j
@Order(1)
@RestControllerAdvice
public class GlobalControllerAdvice {

    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(value = BindException.class)
    public ApiResult<ApiResult.ApiData> violationException(BindException exception) {
        return ApiResult.buildParamFormatErrorResponse(exception.getAllErrors().get(0).getDefaultMessage());
    }

    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(value = ConstraintViolationException.class)
    public ApiResult<ApiResult.ApiData> formatException2(ConstraintViolationException e) {
        Set<ConstraintViolation<?>> constraintViolations = e.getConstraintViolations();

        if (!CollectionUtils.isEmpty(constraintViolations)) {
            String errorMessage = constraintViolations.iterator().next().getMessage();
            return ApiResult.buildParamFormatErrorResponse(errorMessage);
        } else {
            return ApiResult.buildErrorResponse(ErrorStatus.SERVER_ERROR);
        }
    }

    @ExceptionHandler(value = InvalidFileTypeException.class)
    public ApiResult<ApiResult.ApiData> imageException(InvalidFileTypeException e) {
        return ApiResult.buildErrorResponse(e.getCode(), e.getMessage());
    }

    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(value = RequestDataException.class)
    public ApiResult<ApiResult.ApiData> handleRequestParamException(RequestDataException e) {
        return ApiResult.buildErrorResponse(e.getCode(), e.getMsg());
    }

    @ExceptionHandler(value = MissingRequestHeaderException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public ApiResult<ApiResult.ApiData> handleHeaderParameters() {
        RequestDataException exception = new RequestDataException();
        return ApiResult.buildErrorResponse(exception.getCode(), exception.getMsg());
    }

    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(value = InvalidTokenException.class)
    public ApiResult<ApiResult.ApiData> tokenException(InvalidTokenException e) {
        log.info(e.getMsg());
        return ApiResult.buildErrorResponse(e.getCode(), "登录已失效, 请重新登录!");
    }

    @ExceptionHandler(value = {UpdateTableRecordException.class})
    @ResponseStatus(HttpStatus.OK)
    public ApiResult<ApiResult.ApiData> handleDataBaseOperation(UpdateTableRecordException e) {
        return ApiResult.buildErrorResponse(ErrorStatus.SERVICE_NOT_AVAILABLE, e.getMessage());
    }


}
